#include "../../src/detail/redis_impl.hh"
#include "../../src/repo/src/include/root/coroutine/coroutine.h"
#include "../../src/util/time_util.hh"
#include "../framework/unittest.hh"

FIXTURE_BEGIN(test_redis_batch)

CASE(TestDoCommand1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  bool exist = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  auto result = redis.do_command(
      "test", cmd_vec, 1000,
      [&](const kratos::redis::Result &r, std::uint64_t) {
        done = true;
        exist = (r.get_reply() != nullptr);
        r.next_reply();
        exist = (r.get_reply() != nullptr);
      },
      0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(done);
}

CASE(TestDoCommand2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  bool error = false;
  kratos::redis::RedisError code = kratos::redis::RedisError::SUCCESS;
  kratos::redis::CommandVector cmd_vec{"xxxxxxx", "xxxxxxx"};
  auto result = redis.do_command(
      "test", cmd_vec, 1000,
      [&](const kratos::redis::Result &r, std::uint64_t) {
        done = r.is_success();
        error = !r.get_error().empty();
        code = r.get_error_code();
      },
      0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(!done);
  ASSERT_TRUE(error);
  ASSERT_TRUE(code != kratos::redis::RedisError::SUCCESS);
}

CASE(TestDoCommand3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  kratos::redis::CommandVector cmd_vec{"xxxxxxx", "xxxxxxx"};
  auto result = redis.do_command(
      "test", cmd_vec, 1000,
      [&](const kratos::redis::Result &r, std::uint64_t) {
        done = r.is_success();
        throw std::runtime_error("");
      },
      0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(!done);
}

CASE(TestDoCommand4) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  ASSERT_FALSE(redis.do_command(
      "", cmd_vec, 1000,
      [&](const kratos::redis::Result &, std::uint64_t) { done = true; }, 0));
  ASSERT_FALSE(done);
}

CASE(TestDoCommand5) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  ASSERT_FALSE(redis.do_command(
      "ssssss", cmd_vec, 1000,
      [&](const kratos::redis::Result &, std::uint64_t) { done = true; }, 0));
  ASSERT_FALSE(done);
}

CASE(TestDoCommand6) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  kratos::redis::CommandVector cmd_vec;
  ASSERT_FALSE(redis.do_command(
      "test", cmd_vec, 1000,
      [&](const kratos::redis::Result &, std::uint64_t) { done = true; }, 0));
  ASSERT_FALSE(done);
}

CASE(TestDoCommand7) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool done = false;
  bool exist = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  auto result = redis.do_command(
      "test", cmd_vec, 0,
      [&](const kratos::redis::Result &r, std::uint64_t) {
        done = true;
        exist = (r.get_reply() != nullptr);
      },
      0);
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(done);
}

CASE(TestDoCommandCo1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    result = ret->is_success();
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
}

CASE(TestDoCommandCo2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  kratos::redis::CommandVector cmd_vec;
  ASSERT_FALSE(redis.do_command_co("test", cmd_vec, 1000));
}

CASE(TestDoCommandCo3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  ASSERT_FALSE(redis.do_command_co("", "SET k value", 1000));
}

CASE(TestDoCommandCo4) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 0);
    result = ret->is_success();
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
}

CASE(TestDoCommandCo5) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("txxxxest", cmd_vec, 0);
    result = !ret;
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
}

CASE(TestResult1) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  bool retval = false;
  kratos::redis::CommandVector cmd_vec{"SET k value", "SET k value"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(retval);
}

CASE(TestResult2) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::string result;
  bool retval = false;
  kratos::redis::CommandVector cmd_vec{"GET k", "GET k"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result == "value");
  ASSERT_TRUE(retval);
}

CASE(TestResult3) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::size_t result = 0;
  bool retval = false;
  kratos::redis::CommandVector cmd_vec{"GET k", "GET k"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(!result);
  ASSERT_TRUE(!retval);
}

CASE(TestResult4) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  std::size_t result = 0;
  bool retval = false;
  kratos::redis::CommandVector cmd_vec{"EXISTS k", "EXISTS k"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result == 1);
  ASSERT_TRUE(retval);
}

CASE(TestResult5) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  bool retval = false;
  kratos::redis::CommandVector cmd_vec{"EXISTS k", "EXISTS k"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(result);
  ASSERT_TRUE(retval);
}

CASE(TestResult6) {
  kratos::redis::RedisImpl redis(nullptr);
  ASSERT_TRUE(redis.add_host("test", "127.0.0.1", 6379, "", ""));
  bool result = false;
  bool retval = false;
  kratos::redis::CommandVector cmd_vec{"EXISTS xdsss", "EXISTS xdsss"};
  coro_start([&](void *) {
    auto ret = redis.do_command_co("test", cmd_vec, 1000);
    retval = ret->get_return(result);
  });
  auto start = kratos::util::get_os_time_millionsecond();
  while (true) {
    auto ms = kratos::util::get_os_time_millionsecond();
    if (ms - start > 1000) {
      break;
    }
    redis.update(ms);
  }
  ASSERT_TRUE(!result);
  ASSERT_TRUE(retval);
}

FIXTURE_END(test_redis_batch)
